package com.welike.shibo.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.welike.shibo.eneity.*;
import com.welike.shibo.enums.ResultEnum;
import com.welike.shibo.exception.BaseException;
import com.welike.shibo.mapper.VideoMapper;
import com.welike.shibo.service.*;
import com.welike.shibo.utils.*;
import com.welike.shibo.vo.VideoInfoListVO;
import com.welike.shibo.vo.page.FollowVideoPageVo;
import com.welike.shibo.vo.page.VideoPageVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.welike.shibo.utils.Constants.REDIS_UPLOAD_KEY;

/**
 * @author fangyu
 * @version v1.0.0
 * @since 2019-08-20 00:40
 */

@Slf4j
@Service
public class VideoServiceImpl extends ServiceImpl<VideoMapper, Video> implements VideoService {

    /**
     * 文件存储 路径
     * /Users/fangyu/Downloads
     * /root/shortvideo
     */
    @Value("${media.path}")
    public String MEDIA_PATH;
    public String FFMPEG_PATH = "ffmpeg";


    @Autowired
    private VideoMapper videoMapper;

    @Autowired
    private UserService userService;

    @Autowired
    private ZanService zanService;

    @Autowired
    private AudioService audioService;

    @Autowired
    private FansService fansService;

    @Autowired
    private GoodsService goodsService;


    @Autowired
    private CommentsService commentsService;

    @Autowired
    private QiNiuUtil qiNiuUtil;

    @Autowired
    private RedisService redisService;

    /**
     * 通过vid查询封面
     *
     * @param vid 视频id
     * @return cover
     */
    @Override
    public String queryCoverByVid(String vid) {
        return videoMapper.queryCoverPathById(vid);
    }

    @Override
    public String queryDescByVid(String vid) {
        return videoMapper.queryVideoDescById(vid);
    }

    @Override
    public List<VideoPageVo> selectUserPage(int page, int pageSize, String uid, String login_uid) {
        try {
            Page<Video> p = new Page<>(page, pageSize);
            List<VideoPageVo> videoPageVoList = new ArrayList<>();
            videoMapper.selectUidVideoInfoPage(p, uid);
            User user = userService.queryUserByUid(uid);
            for (Video video : p.getRecords()) {
                log.info("video => {}", video);
                VideoPageVo videoPageVo = new VideoPageVo();
                videoPageVo.setVid(video.getId());
                videoPageVo.setUid(uid);
                videoPageVo.setNickName(user.getNickname());
                videoPageVo.setAvatar(user.getAvatar());
                videoPageVo.setLevel(user.getLevel());
                videoPageVo.setAudioName(audioService.queryNameById(video.getAudioId()));
                videoPageVo.setVideoPath(video.getVideoPath());
                videoPageVo.setVideoWidth(video.getVideoWidth());
                videoPageVo.setVideoHeight(video.getVideoHeight());
                videoPageVo.setVideoDesc(video.getVideoDesc());
                videoPageVo.setVideoDuration(video.getVideoDuration());
                videoPageVo.setCoverPath(video.getCoverPath());
                videoPageVo.setCreateTime(video.getCreateTime());
                // 查询关注关系(传入的uid=>fanId和videoPageVo.视频发布者=>uid关系)
                if (login_uid != null) {
                    if (fansService.queryIdByUserIdAndFanId(login_uid, uid) != null) {
                        // 不为空，则为关注关系
                        videoPageVo.setFollowStatus(true);
                    }
                } else {
                    videoPageVo.setFollowStatus(false);
                }
                // 查询点赞关系(传入的uid和视频的点赞关系)
                if (zanService.queryIdByUserIdAndZanObjId(uid, video.getId()) != null) {
                    videoPageVo.setLikeStatus(true);
                }
                if (video.getShopId() != null) {
                    videoPageVo.setGoodsId(video.getShopId());
                    videoPageVo.setGoodsName(goodsService.queryNameByShopId(video.getShopId()));
                }
                videoPageVo.setLikeCounts(video.getLikeCounts());
                videoPageVo.setCommentCounts(video.getCommentCounts());
                videoPageVo.setShareCounts(video.getShareCounts());
                videoPageVo.setVideoUrl(video.getVideoUrl());
                videoPageVoList.add(videoPageVo);
            }
            return videoPageVoList;
        } catch (RuntimeException e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 这里处理登录和未登录返回的首页数据
     *
     * @param page     当前页码
     * @param pageSize 页大小
     * @param userId   用户id
     * @return IPage
     */
    @Override
    public IPage<VideoPageVo> selectIndexPage(int page, int pageSize, String userId) {
        try {
            Page<VideoPageVo> p = new Page<>(page, pageSize);
            // 用户为null，则返回所有随机被打乱的数据
            if (userId == null) {
                p.setRecords(videoMapper.selectIndexPage(p));
            } else {
                // 不为null， 则返回除了自己的视频外所有数据
                p.setRecords(videoMapper.selectIndexPageNotInUserId(p, userId));
            }
            return p;
        } catch (RuntimeException e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    // 处理关注点赞逻辑 => 重新封装首页逻辑
    @Override
    public List<VideoPageVo> queryIndexPage(int page, int pageSize, String uid) {
        List<VideoPageVo> videoPageVoList = new ArrayList<>();
        for (VideoPageVo videoPageVo : this.selectIndexPage(page, pageSize, uid).getRecords()) {
            // 查询关注关系(传入的uid=>fanId和videoPageVo.视频发布者=>uid关系)
            if (fansService.queryIdByUserIdAndFanId(videoPageVo.getUid(), uid) != null) {
                // 不为空，则为关注关系
                videoPageVo.setFollowStatus(true);
            }
            // 查询点赞关系(传入的uid和视频的点赞关系)
            if (zanService.queryIdByUserIdAndZanObjId(uid, videoPageVo.getVid()) != null) {
                videoPageVo.setLikeStatus(true);
            }
            if (videoPageVo.getGoodsId() != null) {
                videoPageVo.setGoodsName(goodsService.queryNameByShopId(videoPageVo.getGoodsId()));
            }
            videoPageVoList.add(videoPageVo);
        }
        return videoPageVoList;
    }

    @Override
    public List<VideoPageVo> queryFollowAndLikeState(int page, int pageSize, String uid, List<VideoPageVo> list) {
        List<VideoPageVo> videoPageVoList = new ArrayList<>();
        for (VideoPageVo videoPageVo : list) {
            // 如果uid不为空，处理点赞关系逻辑
            if (uid != null) {
                // 查询关注关系(传入的uid=>fanId和videoPageVo.视频发布者=>uid关系)
                if (fansService.queryIdByUserIdAndFanId(videoPageVo.getUid(), uid) != null) {
                    // 不为空，则为关注关系
                    videoPageVo.setFollowStatus(true);
                }
                // 查询点赞关系(传入的uid和视频的点赞关系)
                if (videoPageVo.getVid() != null) {
                    if (zanService.queryIdByUserIdAndZanObjId(uid, videoPageVo.getVid()) != null) {
                        videoPageVo.setLikeStatus(true);
                    }
                } else {
                    videoPageVo.setLikeStatus(false);
                }

            }
            if (videoPageVo.getGoodsId() != null) {
                videoPageVo.setGoodsName(goodsService.queryNameByShopId(videoPageVo.getGoodsId()));
            }
            videoPageVoList.add(videoPageVo);
        }
        return videoPageVoList;
    }


    /**
     * 查询关注的人的视频列表
     *
     * @param page     当前页码
     * @param pageSize 页大小
     * @param uidList  关注的人uid列表
     * @return 关注的人视频列表
     */
    @Override
    public IPage<VideoPageVo> selectFollowPage(int page, int pageSize, List<String> uidList) {
        try {
            Page<VideoPageVo> p = new Page<>(page, pageSize);
            videoMapper.selectVideoInfoVOInUserIdList(p, uidList);
            return p;
        } catch (RuntimeException e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * TODO 重做查询关注的人的视频列表
     *
     * @param page     页码
     * @param pageSize 分页大小
     * @param uidList  关注的人uid列表
     * @return List<FollowVideoPageVo>
     */
    @Override
    public List<FollowVideoPageVo> getFollowVideoPageVoList(int page, int pageSize, String uid, List<String> uidList) {
        IPage<VideoPageVo> iPage = this.selectFollowPage(page, pageSize, uidList);
        List<FollowVideoPageVo> followVideoPageVoList = new ArrayList<>();
        for (VideoPageVo videoPageVo : iPage.getRecords()) {
            FollowVideoPageVo followVideoPageVo = new FollowVideoPageVo();
            BeanUtils.copyProperties(videoPageVo, followVideoPageVo);
            String result = zanService.queryIdByUserIdAndZanObjId(uid, videoPageVo.getVid());
            if (result != null) {
                followVideoPageVo.setLikeStatus(true);
            }
            Comments comments = commentsService.selectCommentTop(videoPageVo.getVid());
            log.info("comments ==> {}", comments);
            if (comments != null) {
                FollowVideoPageVo.Comment comment = new FollowVideoPageVo.Comment();
                comment.setCommentUid(comments.getUserId());
                comment.setCommentNickName(userService.queryNickNameByUid(comments.getUserId()));
                comment.setContent(comments.getContent());
                followVideoPageVo.setComment(comment);
            }
            followVideoPageVoList.add(followVideoPageVo);
        }
        return followVideoPageVoList;
    }

    /**
     * 查询视频(vid)收获了多少个赞
     * 查询视频被赞的次数
     *
     * @param vid 视频id
     * @return int
     */
    @Override
    public Integer queryLikeCountsById(String vid) {
        return videoMapper.queryLikeCountsById(vid);
    }

    /**
     * 查询视频被分享的次数
     *
     * @param vid 视频id
     * @return int
     */
    @Override
    public Integer queryShareCountsById(String vid) {
        return videoMapper.queryShareCountsById(vid);
    }

    // 查询用户(userId)发布了多少个视频
    @Override
    public Integer countByUserId(String uid) {
        return videoMapper.countByUserId(uid);
    }

    // 查询用户(userId)收获了多个赞(视频)
    @Override
    public Integer sumForLikeCountsByUserId(String uid) {
        return videoMapper.sumForLikeCountsByUserId(uid);
    }

    @Override
    public String uploadFile(MultipartFile file) throws IOException {
        String fileName = file.getOriginalFilename();
        log.info("uploadFile ==> {}", fileName);
        if (fileName == null) {
            return "error";
        }
        String type = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
        log.info("File Type ==> {}", type);
        InputStream is = file.getInputStream();
        String key = Tools.getYearMonth() + System.currentTimeMillis() + "." + type;
        return qiNiuUtil.upload(is, key);
    }

    @Override
    public Integer countByVideo() {
        return videoMapper.countByVideo();
    }

    @Override
    public IPage<VideoInfoListVO> selectVideoPageVo(Page<VideoInfoListVO> page) {
        return videoMapper.selectVideoPageVo(page);
    }

    // 获取频道-全部视频列表 ==> 分页
    @Override
    public IPage<VideoPageVo> getAllVideoPageVo(int page, int pageSize) {
        return selectIndexPage(page, pageSize, null);
    }

    // 获取频道-同城视频列表 ==> 分页
    @Override
    public IPage<VideoPageVo> getCityVideoPageVo(int page, int pageSize, String city) {
        Page<VideoPageVo> p = new Page<>(page, pageSize);
        return videoMapper.queryCityVideo(p, city);
    }

    // 获取频道-大V视频列表 ==> 分页
    @Override
    public IPage<VideoPageVo> getVipVideoPageVo(int page, int pageSize) {
        // 查找大V
        List<String> uidList = userService.queryAllVipUser();
        try {
            Page<VideoPageVo> p = new Page<>(page, pageSize);
            videoMapper.selectVideoInfoVOInUserIdList(p, uidList);
            return p;
        } catch (RuntimeException e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    // 获取频道-推荐视频列表 ==> 分页
    @Override
    public IPage<VideoPageVo> getHotVideoPageVo(int page, int pageSize) {
        Page<VideoPageVo> p = new Page<>(page, pageSize);
        return videoMapper.queryHotVideo(p);
    }

    /**
     * 通过视频vid查询作者uid
     *
     * @param vid 视频vid
     * @return 作者uid
     */
    @Override
    public String queryUserIdById(String vid) {
        return videoMapper.queryUserIdById(vid);
    }

    // 改变视频状态
    @Override
    public void updateVideoStatus(String id, Integer status) {
        // 如果id为null
        if (null == id) {
            // 抛一个视频不存在的异常
            throw new BaseException(ResultEnum.VIDEO_NOT_EXIST);
        }
        videoMapper.updateStatusById(status, id);
    }

    @Override
    public List<FollowVideoPageVo> searchVideo(int page, int pageSize, String key) {
        int limit = page - 1;
        int offset = limit * pageSize;
        List<Video> videoList = videoMapper.searchVideo(offset, pageSize, key);
        List<FollowVideoPageVo> followVideoPageVoList = new ArrayList<>();
        for (Video video : videoList) {
            FollowVideoPageVo followVideoPageVo = new FollowVideoPageVo();
            BeanUtils.copyProperties(video, followVideoPageVo);
            followVideoPageVo.setVid(video.getId());
            followVideoPageVo.setUid(video.getUserId());
            User user = userService.queryUserByUid(video.getUserId());
            followVideoPageVo.setAvatar(user.getAvatar());
            followVideoPageVo.setNickName(user.getNickname());
            followVideoPageVo.setLevel(user.getLevel());
            Comments comments = commentsService.selectCommentTop(video.getId());
            if (comments != null) {
                FollowVideoPageVo.Comment comment = new FollowVideoPageVo.Comment();
                comment.setCommentUid(comments.getUserId());
                comment.setCommentNickName(userService.queryNickNameByUid(comments.getUserId()));
                comment.setContent(comments.getContent());
                followVideoPageVo.setComment(comment);
            }
            followVideoPageVoList.add(followVideoPageVo);
        }
        return followVideoPageVoList;
    }

    /**
     * 通过uid查询发布的所有的作品id
     *
     * @param uid 用户id
     * @return List(String)
     */
    @Override
    public List<String> findVideoIdByUid(String uid) {
        return videoMapper.findVideoIdByUid(uid);
    }

    @Override
    public String queryVideoUrlByVid(String vid) {
        return videoMapper.queryVideoUrlById(vid);
    }


    // 删除
    @Override
    public JsonResult removeVideo(String id) {
        if (null == id) {
            return ResultUtils.error("视频id不可为空!");
        }
        try {
            videoMapper.deleteById(id);
            commentsService.remove(new QueryWrapper<Comments>().eq("video_id", id));
            zanService.remove(new QueryWrapper<Zan>().eq("zan_obj_id", id));
        } catch (RuntimeException e) {
            return ResultUtils.error("删除失败:" + e.getMessage());
        }
        return ResultUtils.success("删除成功!");
    }

    @Override
    public JsonResult create(JSONObject requestJson, HttpServletRequest request) throws UnknownHostException {
        String id = Tools.getUniqueKey();
        String path;
        try {
            path = IpUtil.getIpCity(request);
        } catch (Exception e) {
            path = "未知";
        }
        String desc = requestJson.getString("desc");
        // 参数限制
        if (desc.length() > 55) {
            return ResultUtils.error(ResultEnum.E_90004.getCode(), "视频描述字段超长（" + desc.length() + "），请注意提交参数");
        }
        String coverUrl = requestJson.getString("img");
        String videoUrl = requestJson.getString("video");
        String shopId = requestJson.getString("goods");
        log.info("shopId ==> {}", shopId);
        Integer duration = requestJson.getIntValue("duration");
        Video video = new Video(id, "10000", "0", path, desc, duration, 720, 1280, coverUrl, videoUrl, shopId);
        this.save(video);
        Map<String, Object> result = new HashMap<>(1);
        result.put("video", video);
        return ResultUtils.success("成功上传", result);
    }

    @Override
    public String compound(MultipartFile file, String audioId, Integer duration) {
        // 合成逻辑
        String uploadPathDB = "/media/video";
        FileOutputStream fileOutputStream = null;
        InputStream inputStream = null;
        // 文件生成目录
        String outputPath = "";
        // 文件名
        String videoOutputName = Tools.getYearMonth() + System.currentTimeMillis() + ".mp4";
        try {
            log.info("audioId ==> {}", audioId);
            String fileName = file.getOriginalFilename();
            if (StringUtils.isNoneBlank(fileName)) {
                // 文件生成目录
                outputPath = MEDIA_PATH + uploadPathDB + "/" + fileName;
                log.info("compound,文件生成目录：outputPath:{}", outputPath);
//                        uploadPathDB += ("/" + fileName);
                File outFile = new File(outputPath);
                if (outFile.getParentFile() != null || !outFile.getParentFile().isDirectory()) {
                    //创建父文件夹
                    outFile.getParentFile().mkdirs();
                }
                fileOutputStream = new FileOutputStream(outFile);
                inputStream = file.getInputStream();
                IOUtils.copy(inputStream, fileOutputStream);
            }
            if (!audioId.equals("0")) {
                MergeVideoMp3 tool = new MergeVideoMp3(FFMPEG_PATH);
                //                uploadPathDB = MEDIA_PATH + uploadPathDB + "/" + videoOutputName;
                String mp3Path = audioService.queryAudioUrlById(audioId);
                String mp3InputPath = MEDIA_PATH + "/media/mp3/" + mp3Path;
                log.info("mp3 => {}", mp3InputPath);
                // 视频输入路径，音频输入路径，时长，合成输出路径名
                outputPath = tool.converetor(outputPath, mp3InputPath, duration, videoOutputName);
            }
            log.info("outputPath ==> {}", outputPath);
            return qiNiuUtil.upload(outputPath, videoOutputName);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    @Override
    public Boolean screenshot(MultipartFile file, String name) {
        JSONObject task1 = new JSONObject();
        JSONObject task2 = new JSONObject();
        String upload_key = REDIS_UPLOAD_KEY + "task";
        String uploadPathDB = "/media/img";
        FileOutputStream fileOutputStream = null;
        InputStream inputStream = null;
        // 视频文件生成目录
        String outputPath = "";
        // 图片文件名
        String imgOutputName = name + ".jpg";
        // 图片任务
        task1.put("name", imgOutputName);
        String videoUploadName = name + ".mp4";
        // 视频任务
        task2.put("name", videoUploadName);
//        String imgOutputName =  Tools.getYearMonth() + System.currentTimeMillis() + ".jpg";
//        String videoUploadName =  Tools.getYearMonth() + System.currentTimeMillis() + ".mp4";
        try {
            String fileName = file.getOriginalFilename();
            if (StringUtils.isNoneBlank(fileName)) {
                // 视频文件生成目录
                outputPath = MEDIA_PATH + uploadPathDB + "/" + fileName;
                log.info("screenshot,视频文件生成目录：outputPath:{}", outputPath);
                File outFile = new File(outputPath);
                // 如果没有文件夹则创建
                if (outFile.getParentFile() != null || !outFile.getParentFile().isDirectory()) {
                    //创建父文件夹
                    outFile.getParentFile().mkdirs();
                }
                // 复制视频文件流
                fileOutputStream = new FileOutputStream(outFile);
                inputStream = file.getInputStream();
                IOUtils.copy(inputStream, fileOutputStream);
                task2.put("path", outputPath);
                // push 视频任务
                redisService.lpush(upload_key, task2.toJSONString());
            }

            // 图片文件输出目录
            String imgOutputPath = MEDIA_PATH + uploadPathDB + "/" + imgOutputName;
            log.info("图片文件输出目录 ==> {}", imgOutputPath);
            MergeVideoMp3 tool = new MergeVideoMp3(FFMPEG_PATH);
            // 截图成功 screenshot(视频输入路径，图片输出路径)
            if (tool.screenshot(outputPath, imgOutputPath)) {
                log.info("outputPath ==> {}", imgOutputName);
                // 七牛云上传 uploadImg(图片输入路径，图片名)
                task1.put("path", imgOutputPath);
                // push 图片任务
                redisService.lpush(upload_key, task1.toJSONString());
            } else {
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
}
